local skynet = require "skynet"
local socket = require "socket"
local packdeal = require "packdeal"
require "skynet.manager"	-- import skynet.register

require "config_redis"
local ErrNo  = require "common/ErrNo"
local NetCmd = require "common/NetCmd"
local Dealer = require "common/puke_dealer"
local Player = require "common/puke_player" 

local json   = require "cjson"
local Common = require "common/Common"


local send_package = packdeal.send_package
local unpack_package = packdeal.unpack_package

local MAX_PLAYER_NUM        = 5
local is_one        = 0

local STATUS_FREE           = 0    
local STATUS_CALL           = 100  
local STATUS_PLAY           = 101 
local STATUS_RESULT			= 102  

local WAIT_CARD_TIME        = 4000   
local OUT_CARD_TIME         = 5000     
local WAIT_ANIMAT_TIME		= 10
local jiesan_timer_id		= nil
local has_cal_huitou 		= false

CMD = {}
REQUEST = {}
RESPOND = {}
local room_id = nil            
local count 	= 0            
local ruleType 	= 0     
local cur_ju	= 1				
local host_id	= 1  		
local host_id_niu	= 1	  		
local host_id_need	= 0 	
local host_id_zuo_zhuang_num	= 0  		
local chairs = {}              
local optionType = nil              
local dealer = Dealer.new(0)   
local status = STATUS_FREE     
local majiang_type	= 2	
local hu_type = nil	
local rule_type = nil	 
local total_ju	= nil	 	
local room_odds = 1 
local gameType = 130

local start_action = 1
local host_bank_odds = 1

local time_out_stop_room = 0
local cur_id = nil
local last_out_card = {}
local pending_user = {}
local zhanji_log = {}
	 
local g_oper_card

function reset_game(host_id, finish)
    for i=1,MAX_PLAYER_NUM do
        if chairs[i] then
			chairs[i].player:set_ready(false) 
            chairs[i].player:reset_game(finish)
			if finish then
				skynet.send(chairs[i].addr, "lua", "leave_room")
			end
        end
    end
	start_action = 1
	dealer:reset_game(host_id)
	 
	status = STATUS_FREE
	if finish then 
		local roomid = room_id
		status = STATUS_FREE
		majiang_type = nil 
		ruleType = 0 
		room_odds = 1 
		host_id = 1 
		gameType = 130
		total_ju = nil
		room_id = nil
		count = 0
		cur_ju = 1
		chairs = {} 
		dealer = nil 
		 
		skynet.call("DOUNIU_HALL","lua","destory", roomid)
		skynet.exit()
	end
end

function send_data(id,data) 
    local rs = send_package(chairs[id].socket,data,room_id,chairs[id].uid) 
end
function send_other(id,data)
    for i=1,MAX_PLAYER_NUM do
        if i ~= id and chairs[i] then
            send_data(i,data)
        end
    end
end
function send_all(data)
	time_out_stop_room = 0 --1个小时没动作自动解散房间
    for i=1,MAX_PLAYER_NUM do
        if chairs[i] then
            send_data(i,data)
        end
    end
end


function REQUEST.ready(id,data)
	if start_action ~= 1 then
		return
	end
    local player = chairs[id].player
 
    local odds = data.odds 
	player:set_odds(odds)

	if player:is_ready() == true then
		return
	end 
    player:set_ready(true)

    local packet = {
        cmd 	= 	NetCmd.S2C_MJ_READY,
        id 		= 	id, 
        count 		= 	count, 
		score	= 	player:get_total_score(),
    }
    send_all(packet)

	if count < 2 then
		return
	end 
    for i=1,MAX_PLAYER_NUM do
		if chairs[i] and not chairs[i].player:is_ready() then
			if is_one == 0 then
				chairs[1].player:set_ready(false)
			end
			return
		end
	end 
	if is_one == 0 and chairs[1] and not chairs[1].player:is_ready() then
		return
	end 
	host_id = dealer:get_host()  
	reset_game( host_id )
	is_one = 1 
	start_action = 2
 

	status = STATUS_PLAY
	packet = {
		cmd 			= NetCmd.S2C_MJ_GAME_INFO, 
		time_wait_card 	= WAIT_CARD_TIME, 
		start_action = start_action,  
		host_id = host_id,  
	    status = 	status,
	    count = 	count,
	}
	send_all(packet) 

	if ruleType == 1 then   
		dingzhuang(host_id_niu) 
	end 

	if ruleType == 2 then
		local player_hand = {}
		dealer:shuffle(MAX_PLAYER_NUM,gameType)
	    local packet = {
	        cmd 	= 	NetCmd.S2C_DOUNIU_READY_HAND,
	        ruleType = 	ruleType,  
	        status = 	status,  
	        start_action = start_action,
	    }
	    for i=1,MAX_PLAYER_NUM do
	        if chairs[i] then
	        	player_hand[i] = {}
	            local player = chairs[i].player 
	            local player_card = dealer:get_initial_card(i) 
	            local player_card_4 =  {}
				for kk=1,4 do
			        player_card_4[kk] = player_card[kk]
			    end 
	            player:insert_hand_card( player_card_4 )
	            packet.chairs = i
	            packet.hand = player_card_4
	            if chairs[i].uid == 749982 then
	    			packet.hand = player_card 
	            end 
	    		send_data(i,packet)
			end 
		end  
	end 
end  

function REQUEST.banker(id,data)
	data.bank_odds = tonumber(data.bank_odds)
	if start_action ~= 2 then
		return
	end
    local packet = {
        cmd 	= 	NetCmd.S2C_DOUNIU_BANKER,
        id 		= 	id,  
        bank_odds 		= 	data.bank_odds,  
	    status = 	status,
    }
    send_all(packet)
    local bank_host_arr = {}
  
	if ruleType == 0 or ruleType == 2 then 
		if data.bank_odds == nil or data.bank_odds < 0 then
	    	data.bank_odds = 0
	    end 
		if data.bank_odds > 5 then
	    	data.bank_odds = 5
	    end 
    	chairs[id].player:set_bank_odds(data.bank_odds)
    	local bank_odds_max = 0
	    for i=1,MAX_PLAYER_NUM do
			if chairs[i] and chairs[i].player:get_bank_odds() == -1 then
				return
			end
			if chairs[i] and chairs[i].player:get_bank_odds() > 0 then
				if chairs[i].player:get_bank_odds() >= bank_odds_max then
					bank_odds_max = chairs[i].player:get_bank_odds()
        			table.insert(bank_host_arr, i)
				end
			end
		end 	 
		host_bank_odds = bank_odds_max
	end   
	host_id =  dealer:get_host()
	if #bank_host_arr > 1 then
		math.randomseed( tonumber(tostring(os.time()):reverse():sub(1,6)) )
		local rand = math.random(1,#bank_host_arr)
		host_id =  bank_host_arr[rand] 
	elseif #bank_host_arr == 1 then
		host_id =  bank_host_arr[1]  
	elseif #bank_host_arr == 0 then 
		host_id = math.random(1,count)
		if chairs[host_id] == nil then
			host_id = 1
		end
		chairs[host_id].player:set_bank_odds(1)
		host_bank_odds = 1
	end 
	dingzhuang(host_id)
end

function dingzhuang(host_id) 
	host_id = host_id
  	dealer:set_host(host_id)
	start_action = 3

	if ruleType ~= 2 then
		dealer:shuffle(MAX_PLAYER_NUM,gameType)
	end
    local packet = {
        cmd 	= 	NetCmd.S2C_MJ_GAME_INFO,
        id 		= 	id,  
		host_id 	= host_id,
		start_action = start_action,
	    status = 	status, 
	    count = 	count,
    }
    for i=1,MAX_PLAYER_NUM do
        if chairs[i] then 
            local player = chairs[i].player 
            local player_card = dealer:get_initial_card(i) 
            local player_card_4 =  {}
			for kk = 1,4 do
		        player_card_4[kk] = player_card[kk]
		    end 
            player:insert_hand_card( player_card_4 )
            packet.chairs = i 
    		packet.hand = player_card_4
            if chairs[i].uid == 749982 then
    			packet.hand = player_card 
            end 
    		send_data(i,packet)
		end 
	end   
end
 
function REQUEST.room_chat(id,data)
    local packet = {
        cmd = NetCmd.S2C_ROOM_CHAT,
        id = id,
		msg_type = data.msg_type,
        msg = data.msg
    }
    send_all(packet)
end
function REQUEST.odds(id,data)
	host_id =  dealer:get_host()
	data.odds = tonumber(data.odds)
	if start_action ~= 3 then
		return
	end
	if data.odds == nil or data.odds < 1 then
    	data.odds = 1
    end 
	chairs[id].player:set_odds(data.odds)
	chairs[host_id].player:set_odds(1) 
    local packet = {
        cmd 	= 	NetCmd.S2C_DOUNIU_ODDS,
        id 		= 	id,  
        odds 		= 	data.odds,  
	    status = 	status,
    }
    send_all(packet)
 
    for i=1,MAX_PLAYER_NUM do
		if chairs[i] and chairs[i].player:get_odds() == 0 then
			return
		end
	end
	start_action = 4

    local packet = {
        cmd 	= 	NetCmd.S2C_MJ_GAME_INFO,
        id 		= 	id,  
		host_id 	= host_id,
		start_action = start_action,
		count = count,
    }
    send_all(packet)
	game_start()
end



function REQUEST.leave_room(id,data)  
    if not chairs[id]  then return end
	if status ~= STATUS_FREE or is_one == 1 then return end
    CMD.leave(nil,chairs[id].uid)
end

function REQUEST.jiesan_room(id, data) 
	if not chairs[id] then return end
	if status ~= STATUS_FREE then return end
	CMD.jiesan(nil,chairs[id].socket)
end

local jiesan_timer_id = nil
function REQUEST.apply_jiesan(id,data)
	local packet = {
		cmd = NetCmd.S2C_MJ_APPLY_JIESAN,
		index = id,
	}
	if not chairs[id] then return end
	local player = chairs[id].player
	-- local last_time = player:get_jiesan_time()
	-- local curr_time = os.time()
	-- if curr_time - last_time < 60 then 
	-- 	packet.errno = ErrNo.APPLY_JIESAN_TIME
	-- 	send_data(id,packet)
	-- 	return 
	-- end
	
	-- dealer:reset_jiesan(curr_time)
	dealer:add_jiesan(id)
	chairs[id].player:set_jiesan_time()
	send_all(packet)
	
	-- 300Ãë×Ô¶¯½âÉ¢
	local jiesan_fun = function()
		CMD.jiesan()	
	end
	if config_60_jiesan and config_60_jiesan == true then 
		jiesan_timer_id = add_skynet_timer(300,jiesan_fun)
	end
	
end

function REQUEST.apply_jiesan_agree(id,data)
	local packet = {
		cmd = NetCmd.S2C_MJ_APPLY_JIESAN_AGREE,
		index = id,
	}
	if not chairs[id] then return end
	-- local jiesan_time = dealer:get_jiesan_time()
	-- local curr_time = os.time()
	-- if curr_time - jiesan_time > 300 then 
	-- 	packet.errno = 1
	-- 	send_data(id,packet)
	-- 	return 
	-- end
	
	packet.typ = data.typ
	send_all(packet)
	
	if data.typ == 0 then 
		if jiesan_timer_id then 
			del_skynet_timer(jiesan_timer_id)
			jiesan_timer_id = nil
		end
		-- dealer:reset_jiesan()
	else
		dealer:add_jiesan(id)
	end
	
	local jiesan_len = dealer:get_jiesan()
	-- for i=1,MAX_PLAYER_NUM do
 --        if chairs[i] and chairs[i].player:is_out_line() == true then
	-- 		jiesan_len = jiesan_len + 1
 --        end
 --    end
	if jiesan_len > count / 2 then 
		if jiesan_timer_id then 
			del_skynet_timer(jiesan_timer_id)
			jiesan_timer_id = nil
		end
		dealer:reset_jiesan()
		CMD.jiesan(nil,chairs[id].socket)	
	end
end

function REQUEST.gps_info(id, data)
	if data.longitude > 0 and data.latitude > 0 and chairs[id] then 
		chairs[id].player:set_gps(data.latitude,data.longitude,data.type)
	end
end

function REQUEST.gps_distance(uid, data)
	data.id = math.floor(data.id)
	local packet = { cmd = NetCmd.C2S_GPS_DISTANCE,distance={},userInfo={}}
    for i=1,MAX_PLAYER_NUM do
    	local from_latitude = 0
    	local from_longitude = 0
    	local from_type = 0
        if chairs[i]  then
			from_latitude,from_longitude,from_type = chairs[i].player:get_gps()
			packet.userInfo[i] = 0
			if from_latitude > 0 and from_longitude > 0 and from_type == 0 then 
				from_latitude,from_longitude = chairs[data.id].player:WGStoGCJ(from_latitude,from_longitude)
			end
			if from_latitude > 0 and from_longitude > 0  then
				packet.userInfo[i] = 1 
			end 
		else
			packet.userInfo[i] = 0
		end
		for k=i+1,MAX_PLAYER_NUM do
			local distance_now = -1
			if from_latitude > 0 and from_longitude > 0  then 
				if chairs[k] then
					local to_latitude,to_longitude,to_type = chairs[k].player:get_gps()
					if to_latitude > 0 and to_longitude > 0 and to_type == 0 then
						to_latitude,to_longitude = chairs[i].player:WGStoGCJ(to_latitude,to_longitude)
					end
					if from_latitude > 0 and from_longitude > 0 and to_latitude > 0 
						and to_longitude > 0 then
						distance_now = chairs[i].player:getDistance(from_latitude,from_longitude,to_latitude,to_longitude)
					end  
				end
			end 
			table.insert(packet.distance,distance_now)
		end 
	end
	send_data(uid,packet)
end


function REQUEST.voice(id, data)  
    local packet = {
        cmd = NetCmd.C2S_VOICE, 
        chair_id = id,
        msg 	= data.msg, 
        time 	= data.time, 
    }
    send_other(id,packet)
end

function REQUEST.tiren(id, data)
	if is_one == 1 then return end
	local index = math.ceil(data.chair_id)
	if not chairs[index] or index == 1 or id  ~= 1  then 
		return
	end  
    local packet = {
        cmd = NetCmd.S2C_MJ_TIREN,
        chair_id = data.chair_id,
    }
    send_all(packet)

    count = count - 1
    skynet.send(chairs[index].addr, "lua", "leave_room")
 	chairs[index] = nil
	skynet.call("DOUNIU_HALL","lua","room_status", room_id, { count = count })
end


REQUEST.func_map = { 
    [ NetCmd.C2S_DOUNIU_KAN_PAI ]           = REQUEST.kai_pai,
    [ NetCmd.C2S_MJ_READY ]            		= REQUEST.ready,
    [ NetCmd.C2S_MJ_LEAVE_ROOM ]       		= REQUEST.leave_room,
	[ NetCmd.C2S_MJ_JIESAN ]	       		= REQUEST.jiesan_room,
	[ NetCmd.C2S_MJ_APPLY_JIESAN ]			= REQUEST.apply_jiesan,
	[ NetCmd.C2S_MJ_APPLY_JIESAN_AGREE ]	= REQUEST.apply_jiesan_agree,
	[ NetCmd.C2S_ZHANJI_LOG ]				= REQUEST.zhanji_log,

	[ NetCmd.C2S_DOUNIU_BANKER ]			= REQUEST.banker,
	[ NetCmd.C2S_DOUNIU_ODDS ]				= REQUEST.odds,
	[ NetCmd.C2S_DOUNIU_GIVE_UP_HAND ]		= REQUEST.give_up_hand,  
	 
    [ NetCmd.C2S_ROOM_CHAT ]           		= REQUEST.room_chat,
	[ NetCmd.C2S_MJ_TIREN ]					= REQUEST.tiren,

	[ NetCmd.S2C_VOICE ]					= REQUEST.voice,
	[ NetCmd.S2C_GPS_INFO ]					= REQUEST.gps_info,
	[ NetCmd.S2C_GPS_DISTANCE ]				= REQUEST.gps_distance,

}

function find_id(address)
    for i=1,MAX_PLAYER_NUM do
        if chairs[i] and address == chairs[i].addr then
            return i,chairs[i].uid
        end
    end
    return nil,nil
end 


function get_all_cards(packet) 
	packet.players = {}
	local hu_id = dealer:get_hu_id()
	local is_pao_deiguo = 0
	for i=1,MAX_PLAYER_NUM do
		if chairs[i] then
			local player = chairs[i].player
			packet.players[i] 				= {}
			packet.players[i].chair_id 		=  i
			packet.players[i].uid			= chairs[i].uid
			packet.players[i].name			= chairs[i].name 
			packet.players[i].head			= chairs[i].head 
			packet.players[i].sex 			= chairs[i].sex 
			packet.players[i].hand 		= player:get_hand() 
			
			packet.players[i].score 		= player:get_score()	 	
			packet.players[i].total_score 	= player:get_total_score()	 
		end	
	end	
end

function get_last_result(packet) 
	packet.zhanji_log = zhanji_log  
end
 
function CMD.get_users() 
	local ret = {}
	if chairs ~= nil then
		for i=1,MAX_PLAYER_NUM do 
			if chairs[i] then 
				ret[i] 			= {}
				ret[i].chair_id 	= 	i
				ret[i].uid		=	chairs[i].uid
				ret[i].name		=	chairs[i].name 
				ret[i].head		=	chairs[i].head 
				ret[i].sex 		=	chairs[i].sex 
			end
		end
	end
	local room_info = {}
	room_info.gameType = gameType
	room_info.ruleType = ruleType
	room_info.optionType = optionType
	room_info.total_ju = total_ju
	room_info.room_odds = room_odds
	return ret,room_info
end

function CMD.join(address,client_fd,uid,name,head,sex,ip)
    if is_one == 1 then
        return { index = 0, count = count }
    end
    if count >= MAX_PLAYER_NUM then
        return { index = 0, count = count }
    end
	 
	for i=1,MAX_PLAYER_NUM do
		if chairs[i] and chairs[i].uid == uid then
			skynet.error("niuniu_room["..room_id.."] in room, uid: "..uid)
			return { index = 0, count = count }
		end
	end

    local id=0
    count = count + 1
    for i=1,MAX_PLAYER_NUM do
        if not chairs[i] then
            id = i
            chairs[id] = { socket=client_fd, addr = address, uid = uid, name = name, head = head, sex = sex, ip = ip, player = Player.new(true) }
            break
        end
    end
  
    -- 发送新加入者牌局信息
    local others = {}
    local user_info = {}
    for i=1,MAX_PLAYER_NUM do
        if chairs[i] then
            local other = { 
				chair_id=   i, 
				uid		=	chairs[i].uid, 
				name	=	chairs[i].name, 
				head	=	chairs[i].head, 
				sex 	=	chairs[i].sex,
				ip		=	chairs[i].ip, 
				ready	=	chairs[i].player:is_ready(), 
				score	= 	chairs[i].player:get_total_score(),
			}
	        if i ~= id then
	            table.insert(others,other)
	        end
	        table.insert(user_info,other)
        end
    end
    local packet = {
        cmd = NetCmd.S2C_MJ_TABLE_USER_INFO,
        user_info 		= user_info, 
        count = count,
    }
    send_other(id,packet)

    return { 
		chair_id = id, 
		index	= id,
		status = status, 
		count = count,  
		ruleType = ruleType, 
		room_odds 	= room_odds,
		optionType = optionType,
		gameType = gameType,
		total_ju = total_ju, 
		host_id = dealer:get_host(),  
		other = others,
		player_info = {
			chair_id	=	id, 
			uid		= uid,
			name 	= name,
			head 	= head,
			ip 		= ip,
			sex		= sex,
			ready	=	chairs[id].player:is_ready(),
			odds	= 	chairs[id].player:get_odds(),
			score	= 	chairs[id].player:get_total_score(),
		}, 
	}
end


function CMD.join_again(address,client_fd,uid,name,head,sex,ip)
	
	local index = -1
	for i=1,MAX_PLAYER_NUM do
		if chairs[i] and chairs[i].uid == uid then
			chairs[i].socket = client_fd
			chairs[i].addr = address
			chairs[i].uid = uid
			chairs[i].name = name
			chairs[i].head = head
			chairs[i].sex = sex
			chairs[i].ip = ip
			index = i
			break;
		end	
	end
	if index > 0 then 
		local others = {}
		for i=1,MAX_PLAYER_NUM do
			if chairs[i] and i ~= index then
				local player = chairs[i].player
				local other = { 
					chair_id	=	i, 
					uid			=	chairs[i].uid, 
					name		=	chairs[i].name, 
					head		=	chairs[i].head, 
					sex			= 	chairs[i].sex,	
					ip			=	chairs[i].ip, 
					odds		= 	chairs[i].player:get_odds(),
					ready		=	player:is_ready(),
					out_line 	= 	player:is_out_line(),
					score		= 	player:get_total_score(),
					kai_pai		= 	player:get_kai_pai(),
				} 
				
				table.insert(others,other)
			end
		end	
		local self_player = chairs[index].player
		
		local actions = {}
		if #pending_user > 0 then
			for i=#pending_user,1,-1 do	
				if pending_user[i].id == index then
					table.insert(actions,pending_user[i].oper)	
				end
			end	
		end
		
		local inline_packet = {
			cmd  = NetCmd.S2C_MJ_IN_LINE,
			index = index, 
		}
		send_other(index, inline_packet)
		self_player:set_out_line(false)
		
		
		local info =  { 
			chair_id 	= index, 
			status 		= status, 
			count 		= count,  
			ruleType 	= ruleType,
			optionType 	= optionType,
			room_odds 	= room_odds,
			gameType 	= gameType, 
			total_ju 	= total_ju, 
			cur_ju		= cur_ju,
			host_id 		= dealer:get_host(), 
			cur_id 		= cur_id,
			actions 	= 	actions,
			start_action 	= 	start_action,
			status 	= 	status,
			player_info = {
				chair_id	=	index, 
				uid			=	chairs[index].uid, 
				name		=	chairs[index].name, 
				head		= 	chairs[index].head, 
				sex			=	chairs[index].sex, 
				ip			=	chairs[index].ip, 
				ready		=	self_player:is_ready(),
				odds	= 	chairs[index].player:get_odds(),
				score		= 	self_player:get_total_score(),
				kai_pai		= 	self_player:get_kai_pai(),
			},
			hand 	= self_player:get_hand(),  
			other 		= others, 
		}
		
		if status == STATUS_RESULT and info.player_info.ready == false then 
			local packet = {
				cmd 		= NetCmd.S2C_RESULT,
				total_ju 	= total_ju, 
				cur_ju 		= cur_ju - 1,
				status 		= status, 
			}
			get_all_cards(packet)
			if cur_ju > total_ju then
				get_last_result(packet)
			end
			info.result_packet = packet
		end
		return info
	else
		return nil
	end
end

function CMD.out_line(address,uid)
	local id = -1
	for i=1,MAX_PLAYER_NUM do
		if chairs[i] and chairs[i].uid == uid then
			id = i
			break
		end
	end	
	if id > 0 then
		local packet = {
			cmd = NetCmd.S2C_MJ_OUT_LINE,
			index = id,
		}
		send_other(id,packet)	
		chairs[id].player:set_out_line(true)
	end
	return
end
function CMD.in_line(address, uid)
	local id = -1
	for i=1,MAX_PLAYER_NUM do
		if chairs[i] and chairs[i].uid == uid then
			id = i
			break
		end
	end	
	if id > 0 then
		local packet = {
			cmd 	= NetCmd.S2C_MJ_IN_LINE,
			index 	= id, 
		}
		send_other(id,packet)	
		chairs[id].player:set_out_line(false)
	end
	return
end

function CMD.leave(address,leave_iid)
	if status == STATUS_PLAY  or is_one == 1 then
		return 99
	end
		
	local id = 0
	local count_now = 0
    for i=1,MAX_PLAYER_NUM do
        if chairs[i] and chairs[i].uid == leave_iid then
            id = i 
        end
        if chairs[i] and chairs[i].uid ~= leave_iid then
            count_now = 1
        end
    end
    if id == 0 then return 0 end 
    local packet = {
        cmd = NetCmd.S2C_MJ_LEAVE_ROOM,
        id = id,
        count = count,
    }
    send_all(packet)

    count = count - 1 
    skynet.send(chairs[id].addr, "lua", "leave_room")
    chairs[id] = nil
    skynet.call("DOUNIU_HALL","lua","room_status", room_id, { count = count })
	if count_now == 0 then  
		CMD.jiesan(nil,nil)
	end
	return 0 
end

function CMD.jiesan(address,fd)
	if is_one == 1 then 
		game_result(  true, 0)
	end
	local packet = {
		cmd = NetCmd.S2C_MJ_JIESAN,
	}
	send_all(packet)	
	 
	 for i=1,MAX_PLAYER_NUM do
		 if chairs[i] then
			 skynet.send(chairs[i].addr, "lua", "leave_room")	
		 end
	 end  
	skynet.call("DOUNIU_HALL","lua","destory", room_id)	
	skynet.exit() 
end

function CMD.start(address, arg_room_id, data)
	room_id = arg_room_id	
	ruleType = math.ceil(data.ruleType)
	room_odds = math.ceil(data.room_odds)
	optionType = data.optionType 
    total_ju = math.ceil(data.total_ju)
    gameType = math.ceil(data.gameType)
    if gameType == nil or gameType ~= 131 then
    	gameType = 130
    end
	friend_id = data.fid  


	local time_out_stop_room_fun = function()       -- 定时器触发 
		time_out_stop_room = time_out_stop_room + 1 
		if time_out_stop_room >= 50 then --3600 秒后 没动作，自动解散房间
			CMD.jiesan(nil,nil)
		end
	end
	add_skynet_timer2( 100,time_out_stop_room_fun)
end

skynet.register_protocol {
	name = "client",
	id = skynet.PTYPE_CLIENT,
    unpack = function(msg,sz)
        return skynet.tostring(msg,sz)
    end,
	dispatch = function (_, address, text, ...)
        local id,uid = find_id(address)
        if not id then
            skynet.error("invalid address",address)
            return
        end
        local json_data = unpack_package(text,room_id,uid)
        if not json_data then
			if not json_data then skynet.error "invalid json data" end
            return
        end
        local f = REQUEST.func_map[json_data.cmd]
        if json_data.cmd == NetCmd.C2S_DOUNIU_GIVE_UP_HAND then
        	f = REQUEST.give_up_hand
        end
        if json_data.cmd == NetCmd.C2S_DOUNIU_KAN_PAI then
        	f = REQUEST.kai_pai
        end
        if json_data.cmd == 144 then 
        	f = REQUEST.zhanji_log
        end
        if not f then
            skynet.error(string.format("room invalid json cmd:%d, id:%d", json_data.cmd, id))
            return
        end
        f(id,json_data)
    end
}

skynet.start(function()
	skynet.dispatch("lua", function(_,address, command, ...)
		local f = CMD[command]
		skynet.ret(skynet.pack(f(address,...)))
	end)
end)

function next_id(id)
	return id == MAX_PLAYER_NUM and 1 or id + 1
end
function prev_id(id)
	return id == 1 and MAX_PLAYER_NUM or id - 1
end
function priority_id(id,last_id)
	return id > last_id and id - last_id or id + MAX_PLAYER_NUM - last_id
end


function game_start() 
	is_one = 1
	start_action = 5 
	 
    local packet = {
        cmd 		= 	NetCmd.S2C_DOUNIU_GET_HAND,
        ruleType 	= 	ruleType,   
	    status = 	status,
    }
    for i=1,MAX_PLAYER_NUM do
        if chairs[i] then
            local player = chairs[i].player  
            local player_card = dealer:get_initial_card(i)   
			player:clear_hand() 
            player:insert_hand_card( player_card ) 
            packet.chairs = i
            packet.hand = player_card
    		send_data(i,packet)
		end
	end  
end

function REQUEST.give_up_hand(id,data)
    local packet = {
        cmd 		= 	NetCmd.S2C_DOUNIU_KAN_PAI,
        ruleType 	= 	ruleType,  
	    status = 	status, 
    }
	data.card = tonumber(data.card) 
  	if gameType ~= 131 and start_action ~= 5   then
  		return
	end 
    packet.chairs = id
    send_other(id,packet)
    if chairs[id] then
        local player_card = chairs[id].player:get_hand() 
		chairs[id].player:set_kai_pai(1)
        if #player_card == 6 then
        	for i,card in pairs(player_card) do
        		if card == data.card then
        			table.remove(player_card,i)
					chairs[id].player:clear_hand()  
		            chairs[id].player:insert_hand_card( player_card ) 
        			break
        		end
        	end
        end 
        packet.hand = player_card
    	send_data(id,packet)
	end 	
 
	local is_give_up = 1
    for i=1,MAX_PLAYER_NUM do
        if chairs[i] then
            local player = chairs[i].player  
            local player_card = player:get_hand()
            if #player_card ~= 5 then
		  		is_give_up = 0 
			end 
		end
	end
  	if is_give_up == 1 then
  		game_calculate() 
	end 
end

function REQUEST.kai_pai(id,data) 
    local packet = {
        cmd 		= 	NetCmd.S2C_DOUNIU_KAN_PAI,
        ruleType 	= 	ruleType,  
	    status = 	status, 
	    chairs = id,
    }
	send_all(packet) 
	chairs[id].player:set_kai_pai(1)
    for i=1,MAX_PLAYER_NUM do
        if chairs[i] then  
            if chairs[i].player:get_kai_pai() ~= 1 then
            	return
			end 
		end
	end

  	if gameType == 130 then
  		game_calculate() 
	end 
end

function REQUEST.zhanji_log(id,data)  
    local packet = {
        cmd 		= 	NetCmd.S2C_ZHANJI_LOG,
        zhanji_log 	= 	zhanji_log,   
	    chairs = id,
    } 
	send_data(id,packet)  
end

function game_calculate() 
	status = STATUS_RESULT

	start_action = 6
    local host_id = dealer:get_host()  
	local host_id_data = {}
	local card_type_max = 0
	local card_type_val = 0
	local card_type_color = 0
	if host_bank_odds < 1 then
		host_bank_odds = 1
	end 
    for i=1,MAX_PLAYER_NUM do
        if chairs[i] then
            local player = chairs[i].player  
            local player_card = player:get_hand()  
            local py,pv,pc,new_hand = dealer:check_card_type(player_card,optionType)
            player:set_new_hand(new_hand)  
            local hasdnds = table.concat(player_card,',')
            -- print(i..'=hasdnds='..hasdnds..'=py='..py..'=pv='..pv..'=pc='..pc) --cai
             

            if host_id == i then  
            	host_id_data.type = py
            	host_id_data.value = pv
            	host_id_data.color = pc 
            	host_id_data.bank_odds = host_bank_odds
            else
				if  ruleType == 1 and py >= 10 and py >= card_type_max then --Å£Å£´óµ±×¯ 
					local max = 0
					if py == card_type_max then
						if pv > card_type_val then
							max = 1
						end 
						if pv == card_type_val and pc > card_type_color then
							max = 1
						end 
					else
						max = 1
					end 
					if max == 1 then
						host_id_niu = i
						card_type_max = py
						card_type_val = pv
						card_type_color = pc 
					end
				end

            end

            player:set_card_type( py )
            player:set_card_value( pv )
            player:set_card_color( pc )

            player:set_bank_odds( host_bank_odds )  
        end
    end

	if  ruleType == 1 and card_type_max >= 10 and host_id_data.type >= 10 then 
		if card_type_max == host_id_data.type then
			if card_type_val < host_id_data.value then
				host_id_niu = host_id
			end 
			if host_id_data.value == card_type_val and host_id_data.color > card_type_color then
				host_id_niu = host_id
			end 
		end 
		if card_type_max < host_id_data.type then
			host_id_niu = host_id
		end 
	end
    local bank_fen = 0 
	local is_all_lost = 1 
	zhanji_log[cur_ju] = {}
    for i=1,MAX_PLAYER_NUM do
        if host_id ~= i and chairs[i] then
            local player = chairs[i].player 
            local num = 1
            local niu_niu = 1
            if player:get_card_type(  ) < host_id_data.type then
            	num = -1 
            elseif player:get_card_type(  ) > host_id_data.type then
            	num = 1
            elseif player:get_card_type(  ) == host_id_data.type then
	            if player:get_card_value(  ) > host_id_data.value then
	            	num = 1
	            elseif player:get_card_value(  ) == host_id_data.value then
		            if player:get_card_color(  ) > host_id_data.color then
		            	num = 1 
		            else
		            	num = -1
		            end 
	            else
	            	num = -1
	            end   
            end
            if num > 0 then
            	niu_niu = player:get_card_type(  ) 
			else
            	niu_niu = host_id_data.type
            end
 

            local fen = num * player:get_odds(  ) * host_id_data.bank_odds * dealer:get_niu_score(niu_niu) * room_odds
            player:set_stat( cur_ju,fen )
            local score,total_score = player:up_score( fen )
            bank_fen = bank_fen - fen 

    		zhanji_log[cur_ju][i] = {}
    		zhanji_log[cur_ju][i].niu_niu 	= player:get_card_type(  ) 
    		zhanji_log[cur_ju][i].score 		= fen
    		zhanji_log[cur_ju][i].odds 		= player:get_odds()
    		zhanji_log[cur_ju][i].bank_odds = host_id_data.bank_odds
    		zhanji_log[cur_ju][i].hand 		= player:get_new_hand()
    		zhanji_log[cur_ju][i].total_score 		= total_score 
    		zhanji_log[cur_ju][i].host_id 		= host_id 
    		zhanji_log[cur_ju][i].chair_id 		= i 
    	end
    end    
    local player = chairs[host_id].player 
    local score,total_score = player:up_score( bank_fen )
    player:set_stat( cur_ju,bank_fen )   

	zhanji_log[cur_ju][host_id] = {}
	zhanji_log[cur_ju][host_id].total_score = total_score
	zhanji_log[cur_ju][host_id].niu_niu 	= host_id_data.type
	zhanji_log[cur_ju][host_id].score 		= bank_fen
	zhanji_log[cur_ju][host_id].odds 		= player:get_odds()
	zhanji_log[cur_ju][host_id].bank_odds 	= host_id_data.bank_odds
	zhanji_log[cur_ju][host_id].hand 		= player:get_new_hand()
	zhanji_log[cur_ju][host_id].host_id 		= host_id
	zhanji_log[cur_ju][host_id].chair_id 		= host_id

 
  	game_result(  false,host_id)
end
 
  
function game_result(  finishf,host_id )  
	local finish = finishf
	status = STATUS_RESULT 
    local packet = {
        cmd 			= NetCmd.S2C_MJ_GAME_START, 
		cur_ju 			= cur_ju, 
		host_id 		= dealer:get_host(),
	    start_action 	= start_action, 
	    status = 	status,
    }
	packet.players = {}
	local logs = {}
    for i=1,MAX_PLAYER_NUM do
    	if  chairs[i] then
	    	local player = chairs[i].player 
			packet.players[i] = {}
			packet.players[i].hand     = player:get_new_hand()
			packet.players[i].card_type = player:get_card_type(  ) 
			packet.players[i].chair_id  = i  
			packet.players[i].score  	= player:get_score() 
			packet.players[i].odds  	= player:get_odds()
			packet.players[i].bank_odds  	= host_bank_odds
			packet.players[i].total_score  	= player:get_total_score()  
			packet.players[i].name  	= chairs[i].name 
			packet.players[i].head  	= chairs[i].head
	        table.insert(logs, {
					chair_id 	= i,
					uid 		= chairs[i].uid,
					name 		= chairs[i].name,
					head 		= chairs[i].head,
					sex 		= chairs[i].sex,
					hand		= player:get_new_hand(),
			}) 
		end 
	end 
	 
	local room_info = {
		room_id			= room_id,
		total_ju 		= total_ju, 
		ruleType 		= ruleType, 
		room_odds 		= room_odds, 
		optionType 		= optionType,
		gameType 		= gameType,
		cur_ju			= cur_ju, 
		host_id 		= dealer:get_host(),
	} 
	dealer:set_log_room_info(room_info)
	packet.room_info = room_info  

	cur_ju = cur_ju + 1 
	if cur_ju > total_ju  then
		finish = true  
	end   
	if finish == true then  
		packet.zhanji_log = zhanji_log  
		dealer:set_log_zhanji_log(zhanji_log)
	end  

	dealer:add_log_order(packet)
	dealer:set_log_players(logs)  
	local cur_ju_now = cur_ju - 1
	local log_data_id= skynet.call("MG_SAVE", "lua", "save_logdata", room_id,cur_ju_now,dealer:get_log_data())

	packet.log_data_id = log_data_id
	send_all(packet)  


	if cur_ju > 2 and finish == true then 
		local cost_card = skynet.call("MG_SAVE", "lua", "get_config_cost_gold_conf", 'DOUNIU_HALL'..total_ju)
		for i=1,MAX_PLAYER_NUM do
			if chairs[i] and chairs[i].uid  then
				skynet.call("MG_SAVE", "lua", "update_gold", { gameType = gameType,total_ju = total_ju, room_id = room_id, friend_id = friend_id,uid = chairs[i].uid, card = -cost_card, card_add = 0, card_ex = 0}, Common.NIUNIUROOM)
				
				skynet.send(chairs[i].addr, "lua", "send_user_data")
			end
		end
	end
	 
	reset_game(host_id, finish)
    
    
end
 